#include "ASStdLib.h"
#ifdef AS_RUN_ON_MRE
#include <string.h>
#include "vmio.h"
#elif defined(AS_RUN_ON_SKY)
#include "mrc_base.h"
#endif
#include "..\tool\ASLog.h"

static ASWCHAR s_as_tmp_wstr_1[128];
static ASWCHAR s_as_tmp_wstr_2[128];
static ASCHAR s_as_astr[512];

typedef struct
{
    ASVOID* ptr;
    ASINT size;
} as_mem_info;

#define AS_MAX_MEM_INFO (2<<10)
static as_mem_info s_as_mem_info[AS_MAX_MEM_INFO];

#if defined(AS_RUN_ON_MRE)
#define AS_UNICODE_STR_BUFFER_LEN (2<<10)
static ASWCHAR s_as_unicode_str[AS_UNICODE_STR_BUFFER_LEN];
#endif


ASVOID* as_memset(ASVOID *dst, ASINT ch, ASUINT size)
{
#if defined(AS_RUN_ON_MRE)
    return memset(dst, ch, size);
#elif defined(AS_RUN_ON_SKY)
    return mrc_memset(dst, ch, size);
#endif
}

ASVOID* as_memcpy(ASVOID *dst, ASVOID *src, ASUINT count)
{
#if defined(AS_RUN_ON_MRE)
    return memcpy(dst, src, count);
#elif defined(AS_RUN_ON_SKY)
    return mrc_memcpy(dst, src, count);
#endif
}

ASINT as_strlen(ASSTR str)
{
#if defined(AS_RUN_ON_MRE)
    return strlen(str);
#elif defined(AS_RUN_ON_SKY)
    return mrc_strlen(str);
#endif
}

ASINT as_strcmp(const ASSTR s1, const ASSTR s2)
{
#if defined(AS_RUN_ON_MRE)
    return strcmp(s1, s2);
#elif defined(AS_RUN_ON_SKY)
    return mrc_strcmp(s1, s2);
#endif
}

ASSTR as_strcpy(ASSTR dest, ASSTR src)
{
#if defined(AS_RUN_ON_MRE)
    return strcpy(dest, src);
#elif defined(AS_RUN_ON_SKY)
    return mrc_strcpy(dest, src);
#endif
}

ASINT as_atoi(ASSTR str)
{
    return atoi(str);
}

ASINT as_wstrlen(ASWSTR wstr)
{
#if defined(AS_RUN_ON_MRE)
    return vm_wstrlen(wstr);
#elif defined(AS_RUN_ON_SKY)
    return mrc_wstrlen((char*)wstr) / 2;
#endif
}

ASWSTR as_ucs2_from_gb2312(ASSTR gb_str)
{
#if defined(AS_RUN_ON_MRE)
    as_memset(s_as_unicode_str, 0, sizeof(s_as_unicode_str));
    vm_gb2312_to_ucs2(s_as_unicode_str, sizeof(s_as_unicode_str), gb_str);
    return s_as_unicode_str;
#elif defined(AS_RUN_ON_SKY)
    ASINT err, size;
    return (ASWSTR)mrc_c2u(gb_str, &err, &size);
#endif
}

ASWSTR as_ufg_tmp(ASINT idx, ASSTR gbs)
{
    ASINT err, size;
    ASWSTR wstr;
    ASWSTR dst_str;
    wstr = mrc_c2u(gbs, &err, &size);

    if(idx == 0)
    {
        dst_str = s_as_tmp_wstr_1;
        as_memset(s_as_tmp_wstr_1, 0, sizeof(s_as_tmp_wstr_1));
    }
    else
    {
        dst_str = s_as_tmp_wstr_2;
        as_memset(s_as_tmp_wstr_2, 0, sizeof(s_as_tmp_wstr_2));
    }

    as_wstrcpy(dst_str, wstr);
    return dst_str;
}

ASVOID as_wstrncpy(ASWSTR dst_wstr, const ASWSTR src_wstr, ASINT cnts)
{
    ASINT len, i, tar_len;

    if(!dst_wstr || !src_wstr || as_wstrlen(src_wstr) <= 0)
        return;

    len = as_wstrlen(src_wstr);

    if(cnts == -1)
    {
        tar_len = len;
    }
    else
    {
        tar_len = AS_MIN(len, cnts);
    }

    for(i = 0; i < tar_len; i++)
    {
        *(dst_wstr + i) = *(src_wstr + i);
    }

    *(dst_wstr + tar_len) = 0;
}


ASVOID as_wstrcpy(ASWSTR dst_wstr, const ASWSTR src_wstr)
{
    as_wstrncpy(dst_wstr, src_wstr, -1);
}

ASVOID as_wstrcat(ASWSTR dst_wstr, ASWSTR cat_wstr)
{
    ASINT dst_len, len, i;

    if(!dst_wstr || !cat_wstr || as_wstrlen(cat_wstr) <= 0)
        return;

    len = as_wstrlen(cat_wstr);
    dst_len = as_wstrlen(dst_wstr);

    for(i = 0; i < len; i++)
    {
        *(dst_wstr + dst_len + i) = *(cat_wstr + i);
    }
}

ASINT as_wstrcmp(ASWSTR dst_wstr, ASWSTR src_wstr)
{
    ASINT src_len, dst_len, i;

    //TODO
    if(!dst_wstr || as_wstrlen(dst_wstr) <= 0 || !src_wstr || as_wstrlen(src_wstr) <= 0 )
        return -1;

    src_len = as_wstrlen(src_wstr);
    dst_len = as_wstrlen(dst_wstr);

    if(src_len != dst_len)
        return -1;

    for(i = 0; i < src_len; i++)
    {
        if(*(dst_wstr + i) != *(src_wstr + i))
            return -1;
    }

    return 0;
}

ASINT as_ucs2_to_ascii(ASSTR dst, ASWSTR src)
{
    ASINT wlen, i;
    ASWCHAR src_c;

    if(!dst || !src)
        return AS_INVALID_PARAM;

    wlen = as_wstrlen(src);

    if(wlen <= 0)
        return AS_INVALID_PARAM;

    for(i = 0; i < wlen; i++)
    {
        src_c = *(src + i);
#ifdef BIG_ENDIAN
        *(dst + i) = (ASWCHAR)(src_c);
#else
        *(dst + i) = (ASCHAR)(src_c >> 8);
#endif
    }

    *(dst + i) = ASNULL;
    return AS_OK;
}

ASINT as_ascii_to_ucs2(ASWSTR dst, ASSTR src)
{
    ASINT alen, i;
    ASCHAR src_c;

    if(!dst || !src)
        return AS_INVALID_PARAM;

    alen = as_strlen(src);

    if(alen <= 0)
        return AS_INVALID_PARAM;

    for(i = 0; i < alen; i++)
    {
        src_c = *(src + i);
#ifdef BIG_ENDIAN
        *(dst + i) = (ASWCHAR)(src_c);
#else
        *(dst + i) = (ASWCHAR)(src_c << 8);
#endif
    }

    *(dst + i) = ASNULL;
    return AS_OK;
}

ASWSTR as_ucs2_from_ascii(ASSTR astr)
{
    as_memset(s_as_tmp_wstr_1, 0, sizeof(s_as_tmp_wstr_1));
    as_ascii_to_ucs2(s_as_tmp_wstr_1, astr);
    return s_as_tmp_wstr_1;
}

ASSTR as_ascii_from_ucs2(ASWSTR ucs2_str)
{
    as_memset(s_as_astr, 0, sizeof(s_as_astr));
    as_ucs2_to_ascii(s_as_astr, ucs2_str);
    return s_as_astr;
}


static ASINT as_mem_find_idx(void* ptr, ASINT* size)
{
    ASINT i;

    for(i = 0; i < AS_MAX_MEM_INFO; i++)
    {
        if(s_as_mem_info[i].ptr == ptr)
        {
            if(size)
                *size = s_as_mem_info[i].size;

            return i;
        }
    }

    return -1;
}

static void as_mem_save_info(void* ptr, ASINT size)
{
    ASINT idx = as_mem_find_idx(NULL, NULL);

    if(idx < 0)
        return;

    s_as_mem_info[idx].ptr = ptr;

    if(!ptr)
        s_as_mem_info[idx].size = 0;
    else
        s_as_mem_info[idx].size = size;

    as_log_mem("[as-memory][alloc] idx[%d],ptr[0x%x],size[%d]", idx, ptr, size);
}

static void as_mem_remove_info(void* ptr)
{
    ASINT idx = as_mem_find_idx(ptr, NULL);

    if(idx < 0)
        return;

    as_log_mem("[as-memory][free] idx[%d],ptr[0x%x],size[%d]", idx, s_as_mem_info[idx].ptr, s_as_mem_info[idx].size);
    as_memset(&s_as_mem_info[idx], 0, sizeof(as_mem_info));
}

ASVOID* as_calloc(ASINT size)
{
    ASVOID* ptr = ASNULL;
#if defined(AS_RUN_ON_MRE)
    ptr = vm_calloc(size);
#elif defined(AS_RUN_ON_SKY)
    ptr = mrc_malloc(size);

    if(ptr)
    {
        as_memset(ptr, 0, size);
    }

#endif
#ifdef AS_LOG_MEM_ENABLE

    if(ptr)
    {
        as_mem_save_info(ptr, size);
    }
    else
    {
        as_log_mem("[as-memory] <warning>  calloc failed!");
    }

#endif//AS_LOG_MEM_ENABLE
    return ptr;
}

ASVOID* as_malloc(ASINT size)
{
    ASVOID* ptr = ASNULL;
#if defined(AS_RUN_ON_MRE)
    ptr = vm_malloc(size);
#elif defined(AS_RUN_ON_SKY)
    ptr = mrc_malloc(size);
#endif
#ifdef AS_LOG_MEM_ENABLE

    if(ptr)
    {
        as_mem_save_info(ptr, size);
    }
    else
    {
        as_log_mem("[as-memory] <warning>  malloc failed!");
    }

#endif//AS_LOG_MEM_ENABLE
    return ptr;
}

ASVOID* as_realloc(ASVOID* ptr, ASINT size)
{
    ASVOID* dst = ASNULL;
    ASINT ori_size, idx;

    if(!ptr)
        return dst;

    idx = as_mem_find_idx(ptr, &ori_size);

    if(idx < 0)
        return dst;

    dst = as_calloc(size);

    if(!dst)
        return dst;

    as_mem_save_info(dst, size);
    as_memcpy(dst, ptr, ori_size);
    as_free(ptr);
    return dst;
}

ASVOID as_free(ASVOID* ptr)
{
    if(!ptr)
        return;

#if defined(AS_RUN_ON_MRE)
    vm_free(ptr);
#elif defined(AS_RUN_ON_SKY)
    mrc_free(ptr);
#endif
#ifdef AS_LOG_MEM_ENABLE
    as_mem_remove_info(ptr);
#endif//AS_LOG_MEM_ENABLE
}

ASINT as_file_open(ASSTR gb_path, as_file_op_mode mode)
{
#if defined(AS_RUN_ON_MRE)
    ASWSTR wpath = as_ucs2_from_gb2312(gb_path);

    switch(mode)
    {
        case AS_FILE_RO:
            return vm_file_open(wpath, MODE_READ, ASTRUE);

        case AS_FILE_WO:
            return vm_file_open(wpath, MODE_APPEND, ASTRUE);

        case AS_FILE_RW:
            return vm_file_open(wpath, MODE_WRITE, ASTRUE);

        case AS_FILE_NEW:
            return vm_file_open(wpath, MODE_CREATE_ALWAYS_WRITE, ASTRUE);

        default:
            return -1;
    }

#elif defined(AS_RUN_ON_SKY)
    ASINT fh;

    switch(mode)
    {
        case AS_FILE_RO:
            fh = mrc_open(gb_path, MR_FILE_RDONLY);
            break;

        case AS_FILE_WO:
            fh = mrc_open(gb_path, MR_FILE_WRONLY);
            break;

        case AS_FILE_RW:
            fh = mrc_open(gb_path, MR_FILE_RDWR);
            break;

        case AS_FILE_NEW:
            as_file_delete(gb_path);
            fh = mrc_open(gb_path, MR_FILE_RDWR | MR_FILE_CREATE);
            break;

        default:
            fh = -1;
    }

    if(fh <= 0)
        return -1;
    else
        return fh;

#endif
}
ASVOID as_file_read(ASINT fh, ASVOID* data_p, ASINT len, ASINT* read)
{
#if defined(AS_RUN_ON_MRE)
    vm_file_read(fh, data_p, len, read);
#elif defined(AS_RUN_ON_SKY)
    ASINT readen;
    readen = mrc_read(fh, data_p, len);

    if(read)
        *read = readen;

#endif
}
ASVOID as_file_write(ASINT fh, ASVOID* data_p, ASINT len, ASINT* write)
{
#if defined(AS_RUN_ON_MRE)
    vm_file_write(fh, data_p, len, write);
#elif defined(AS_RUN_ON_SKY)
    ASINT written;
    written = mrc_write(fh, data_p, len);

    if(write)
        *write = written;

#endif
}
ASINT as_file_seek(ASINT fh, ASINT offset, as_file_seek_type seek_type)
{
    ASINT ret = -1;
#if defined(AS_RUN_ON_MRE)

    switch(seek_type)
    {
        case AS_FILE_BEGIN:
            ret = vm_file_seek(fh, offset, BASE_BEGIN);
            break;

        case AS_FILE_CURR:
            ret = vm_file_seek(fh, offset, BASE_CURR);
            break;

        case AS_FILE_END:
            ret = vm_file_seek(fh, offset, BASE_END);
            break;

        default:
            break;
    }

#elif defined(AS_RUN_ON_SKY)

    switch(seek_type)
    {
        case AS_FILE_BEGIN:
            ret = mrc_seek(fh, offset, MR_SEEK_SET);
            break;

        case AS_FILE_CURR:
            ret = mrc_seek(fh, offset, MR_SEEK_CUR);
            break;

        case AS_FILE_END:
            ret = mrc_seek(fh, offset, MR_SEEK_END);
            break;

        default:
            break;
    }

#endif
    return ret;
}
ASVOID as_file_close(ASINT fh)
{
#if defined(AS_RUN_ON_MRE)
    vm_file_close(fh);
#elif defined(AS_RUN_ON_SKY)
    mrc_close(fh);
#endif
}

ASVOID as_file_delete(ASSTR gb_path)
{
#if defined(AS_RUN_ON_MRE)
    ASWSTR wpath = as_ucs2_from_gb2312(gb_path);
    vm_file_delete(wpath);
#elif defined(AS_RUN_ON_SKY)
    mrc_remove(gb_path);
#endif
}

ASVOID as_file_rename(ASSTR dst_gb_path, ASSTR src_gb_path)
{
#if defined(AS_RUN_ON_MRE)
    ASWSTR dst_path = as_ufg_tmp(0, dst_gb_path);
    ASWSTR src_path = as_ufg_tmp(0, src_gb_path);
    vm_file_rename(dst_path, src_path);
#elif defined(AS_RUN_ON_SKY)
    mrc_rename(src_gb_path, dst_gb_path);
#endif
}

as_ret as_filedir_create(ASSTR gb_path)
{
#if defined(AS_RUN_ON_MRE)
#elif defined(AS_RUN_ON_SKY)

    if(mrc_mkDir(gb_path) == MR_SUCCESS)
        return AS_OK;
    else
        return AS_INVALID_PARAM;

#endif
}

as_ret as_filedir_delete(ASSTR gb_path)
{
#if defined(AS_RUN_ON_MRE)
#elif defined(AS_RUN_ON_SKY)

    if(mrc_rmDir(gb_path) == MR_SUCCESS)
        return AS_OK;
    else
        return AS_INVALID_PARAM;

#endif
}

ASINT as_inter_file_get_filesize(ASSTR gb_name)
{
    ASINT file_size = 0;
    ASUINT8* file_buffer = NULL;

    if(!gb_name)
        return file_size;

    mrc_readFileFromMrpEx(ASNULL, gb_name, &file_buffer, &file_size, 5);
    return file_size;
}

ASINT as_find_first(const ASSTR gb_str, ASSTR out_path, ASINT out_path_buf_len)
{
#if defined(AS_RUN_ON_MRE)
#elif defined(AS_RUN_ON_SKY)
    return mrc_findStart(gb_str, out_path, out_path_buf_len);
#endif
}
as_ret as_find_next(ASINT find_handle, ASSTR out_path, ASINT out_path_buf_len)
{
#if defined(AS_RUN_ON_MRE)
#elif defined(AS_RUN_ON_SKY)

    if(mrc_findGetNext(find_handle, out_path, out_path_buf_len) == MR_SUCCESS)
        return AS_OK;
    else
        return AS_INTERNAL_ERROR;

#endif
}
as_ret as_find_end(ASINT find_handle)
{
#if defined(AS_RUN_ON_MRE)
#elif defined(AS_RUN_ON_SKY)

    if(mrc_findStop(find_handle) == MR_SUCCESS)
        return AS_OK;
    else
        return AS_INTERNAL_ERROR;

#endif
}

ASVOID as_inter_file_load_data_patial(ASSTR gb_name, ASUINT8** out_buffer, ASINT* out_len,
                                      ASINT offset_from_begin, ASINT len_want_read)
{
    if(!gb_name || *out_buffer != ASNULL)
        return;

    mrc_readFileFromMrpExPart(ASNULL, gb_name, out_buffer, out_len, offset_from_begin, len_want_read);
}

ASVOID as_inter_file_load_data(ASSTR gb_name, ASUINT8** out_buffer, ASINT* out_len)
{
    if(!gb_name || *out_buffer != ASNULL)
        return;

    mrc_readFileFromMrpEx(ASNULL, gb_name, out_buffer, out_len, 0);
}

ASVOID as_get_time(as_time* time_p)
{
    mr_datetime time;

    if(!time_p)
        return;

    mrc_getDatetime(&time);
    time_p->year = time.year;
    time_p->month = time.month;
    time_p->day = time.day;
    time_p->hour = time.hour;
    time_p->minute = time.minute;
    time_p->second = time.second;
    time_p->week = as_get_week(time_p->year, time_p->month, time_p->day);
}

ASBOOL as_get_if_leap_year(ASUINT16 year)
{
    if(year % 400 == 0
       || ((year % 100 != 0) && (year % 4 == 0)))
        return ASTRUE;
    else
        return ASFALSE;
}

ASUINT8 as_get_days_of_month(ASUINT16 year, ASUINT8 month)
{
    if(month == 1 ||
       month == 3 ||
       month == 5 ||
       month == 7 ||
       month == 8 ||
       month == 10 ||
       month == 12)
    {
        return 31;
    }
    else if(month == 4 ||
            month == 6 ||
            month == 9 ||
            month == 11)
    {
        return 30;
    }
    else
    {
        // Check leap year for Feb
        if(as_get_if_leap_year(year))
        {
            return 29;
        }
        else
        {
            return 28;
        }
    }
}

ASUINT8 as_get_week(ASUINT16 year, ASUINT8 month, ASUINT8 day)
{
    /*Julius Christian Johannes Zeller*/
    ASINT c, y, week;

    if(month == 1 || month == 2)
    {
        year--;
        month += 12;
    }

    c = year / 100;
    y = year % 100;
    week = (y + y / 4 + c / 4 - 2 * c + (26 * (month + 1)) / 10 + day - 1) % 7;

    while(week < 0)
    {
        week += 7;
    }

    week %= 7;
    return (ASUINT8)week;
}

ASUINT16 as_get_day_of_year(ASUINT16 year, ASUINT8 month, ASUINT8 day)
{
    ASUINT16 days = 0;
    ASINT i;

    for(i = 1; i < month; i++)
    {
        days += as_get_days_of_month(year, i);
    }

    days += day;
    return days;
}

void as_set_days_of_year_to_time(as_time* time_p, ASUINT days)
{
    ASUINT left_days, days_of_month, month;

    if(!time_p || days < 1 || days > as_get_day_of_year(time_p->year, 12,
            as_get_days_of_month(time_p->year, 12)))
        return;

    left_days = days;
    month = 1;
    days_of_month = as_get_days_of_month(time_p->year, month);

    while(left_days > days_of_month)
    {
        month++;
        left_days -= days_of_month;
        days_of_month = as_get_days_of_month(time_p->year, month);
    }

    time_p->month = month;
    time_p->day = left_days;
}

ASUINT8 as_get_week_of_year(ASUINT16 year, ASUINT8 month, ASUINT8 day)
{
    ASUINT16 days = as_get_day_of_year(year, month, day);
    ASUINT8 week = as_get_week(year, 1, 1);
    ASUINT8 day_ad;
    ASUINT8 weeks = 0;
    day_ad = 7 - week;
    days -= day_ad;
    weeks += 1 + days / 7;

    if(days % 7 != 0)
        weeks += 1;

    return weeks;
}

ASBOOL as_get_if_same_week(as_time time1, as_time time2)
{
    ASUINT8 weeks1 = as_get_week_of_year(time1.year, time1.month, time1.day);
    ASUINT8 weeks2 = as_get_week_of_year(time2.year, time2.month, time2.day);

    if(weeks1 == weeks2)
        return ASTRUE;
    else
        return ASFALSE;
}

ASINT32 as_get_days(as_time time1, as_time time2)
{
    ASUINT16 days1 = as_get_day_of_year(time1.year, time1.month, time1.day);
    ASUINT16 days2 = as_get_day_of_year(time2.year, time2.month, time2.day);
    return (ASINT32)days1 - (ASINT32)days2;
}

//ASVOID as_array_quick_sort(void* a,ASINT len,as_sort_comparer comparer,as_sort_exchanger exchanger)
//{
//    ASINT   _i_, _j_, _p_, _stacki_, _start_, _end_;
//    ASINT   _startStack_[64];
//    ASINT   _endStack_[64];
///* can sort up to 2^64 elements */
//    if(!a || !comparer || !exchanger)
//        return;
//
//    //type  _tmp_;
//    _startStack_[0] = 0;
//    _endStack_[0] = (len);
//    _stacki_ = 1;
//    while (_stacki_ > 0)
//    {
//        _stacki_ --;
//        _start_ = _startStack_[_stacki_];
//        _end_ = _endStack_[_stacki_];
//        while (_end_ - _start_ > 2)
//        {
//            _p_ = _start_;
//            _i_ = _start_ + 1;
//            _j_ = _end_ - 1;
//            while (_i_<_j_)
//            {
//                for(; _i_<=_j_ && comparer(((a)[_i_]),((a)[_p_]))<=0; _i_++) ;
//                    if (_i_ > _j_)
//                    {
//                        /* all remaining elements lesseq than pivot */
//                        exchanger(a, _j_, _p_);
//                        _i_ = _j_;
//                    }
//                    else
//                    {
//                    for(; _i_<=_j_ && comparer(((a)[_j_]),((a)[_p_]))>=0; _j_--) ;
//                        if (_i_ > _j_)
//                        {
//                            /* all remaining elements greater than pivot */
//                            exchanger(a, _j_, _p_);
//                            _i_ = _j_;
//                        } else if (_i_ < _j_)
//                        {
//                        exchanger(a, _i_, _j_);
//                        if (_i_+2 < _j_) {_i_++; _j_--;}
//                        else if (_i_+1 < _j_) _i_++;
//                        }
//                    }
//            }
//            /* O.K. i==j and pivot is on a[i] == a[j] */
//            /* handle recursive calls without recursion */
//            if (_i_-_start_ > 1 && _end_-_j_ > 1)
//            {
//                /* two recursive calls, use array-stack */
//                if (_i_-_start_ < _end_-_j_-1)
//                {
//                    _startStack_[_stacki_] = _j_+1;
//                    _endStack_[_stacki_] = _end_;
//                    _stacki_ ++;
//                    _end_ = _i_;
//                }
//                else
//                {
//                _startStack_[_stacki_] = _start_;
//                _endStack_[_stacki_] = _i_;
//                _stacki_ ++;
//                _start_ = _j_+1;
//                }
//            }
//            else
//            {
//                if (_i_-_start_ > 1)
//                {
//                    _end_ = _i_;
//                }
//                else
//                {
//                _start_ = _j_+1;
//                }
//            }
//        }
//        if (_end_ - _start_ == 2)
//        {
//            if (comparer(((a)[_start_]),((a)[_end_-1])) > 0) {
//                exchanger(a, _start_, _end_-1);
//            }
//        }
//    }
//}
//}